package com.example.mp.config;

import lombok.extern.log4j.Log4j2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;


/***
 * @Author: hf
 * @Description: 线程池设置
 * @Date: 2023/10/30 16:24
 */
@Configuration
@EnableAsync
@Log4j2
public class ExecutorConfig {

    @Bean(name = "asyncServiceExecutor")
    public Executor asyncServiceExecutor() {
        int cores = Runtime.getRuntime().availableProcessors(); //获取可用的处理器核心数
        //CPU密集型 cores = 2 * cores; IO密集型 cores = cores + 1;
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(cores);
        //配置最大线程数
        executor.setMaxPoolSize(cores);
        //配置队列大小
        executor.setQueueCapacity(99999);
        /***
         * 1.ArrayBlockingQueue
         * 基于数组的有界阻塞队列，按FIFO排序。新任务进来后，会放到该队列的队尾，有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后，
         * 再有新任务进来，则会将任务放入该队列的队尾，等待被调度。如果队列已经是满的，则创建一个新线程，如果线程数量已经达到maxPoolSize，则会执行拒绝策略。
         * 2.LinkedBlockingQuene
         * 基于链表的无界阻塞队列（其实最大容量为Interger.MAX），按照FIFO排序。由于该队列的近似无界性，当线程池中线程数量达到corePoolSize后，再有新任务进来，
         * 会一直存入该队列，而不会去创建新线程直到maxPoolSize，因此使用该工作队列时，参数maxPoolSize其实是不起作用的。
         * 3.SynchronousQuene
         * 一个不缓存任务的阻塞队列，生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时，不会缓存，而是直接被调度执行该任务，
         * 如果没有可用线程，则创建新线程，如果线程数量达到maxPoolSize，则执行拒绝策略。
         * 4.PriorityBlockingQueue
         * 具有优先级的无界阻塞队列，优先级通过参数Comparator实现。
         * 5.LinkedTransferQueue
         * 可以自己控制放元素是否需要阻塞线程，比如使用四个添加元素的方法就不会阻塞线程
         * 6.LinkedBlockingDeque
         * 7.DelayQueue 数据结构
         */

        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("async-service-");
        /**
         * 1、AbortPolicy（线程池默认）：如果线程池中没有空闲线程且达到了最大数，阻塞队列满了，此时再来任务的话会直接抛出异常
         * 2、CallerRunsPolicy：哪个线程交给线程池这个任务就会让哪个线程自己去执行这个任务
         * 3、DiscardPolicy：任务满了之后，会直接丢掉任务，并且不抛出异常
         * 4、DiscardOldestPolicy：任务满了之后，再来的任务会尝试去和最早的竞争，竞争不过就直接丢弃，也不抛出异常
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }
}